﻿// =====================================================================
//
//  This file is part of the Microsoft Dynamics CRM SDK code samples.
//
//  Copyright (C) Microsoft Corporation.  All rights reserved.
//
//  This source code is intended only as a supplement to Microsoft
//  Development Tools and/or on-line documentation.  See these other
//  materials for detailed information regarding Microsoft code samples.
//
//  THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//
// =====================================================================
#region

using System;
using System.ComponentModel;
using System.ServiceModel;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using SL.IdentityModel.Protocols.WSTrust;


#endregion

namespace Microsoft.Xrm.Sdk
{
	interface OrganizationMethods
	{
		void Create(Entity entity);
		event EventHandler<CreateCompletedEventArgs> CreateCompleted;

		void Retrieve(string entityName, Guid id, ColumnSet columnSet);
		event EventHandler<RetrieveCompletedEventArgs> RetrieveCompleted;

		void Delete(string entityName, Guid id);
		event EventHandler<AsyncCompletedEventArgs> DeleteCompleted;

		void Update(Entity entity);
		event EventHandler<AsyncCompletedEventArgs> UpdateCompleted;

		void RetrieveMultiple(QueryBase query);
		event EventHandler<RetrieveMultipleCompletedEventArgs> RetrieveMultipleCompleted;

		void Associate(string entityName, Guid entityId, Relationship relationship,
									   EntityReferenceCollection relatedEntities);
		event EventHandler<AsyncCompletedEventArgs> AssociateCompleted;

		void Disassociate(string entityName, Guid entityId, Relationship relationship,
									   EntityReferenceCollection relatedEntities);
		event EventHandler<AsyncCompletedEventArgs> DisassociateCompleted;
	}

	public sealed class OrganizationServiceProxy :
		ServiceClient<IOrganizationService, OrganizationServiceClient, OrganizationRequest, ExecuteCompletedEventArgs>,
		OrganizationMethods
	{
		public OrganizationServiceProxy(Uri serviceUrl)
			: base(serviceUrl)
		{
		}

		public OrganizationServiceProxy(IServiceConfiguration<IOrganizationService> serviceConfiguration)
			: base(serviceConfiguration)
		{
		}

		public OrganizationServiceProxy(IServiceConfiguration<IOrganizationService> serviceConfiguration,
								   RequestSecurityTokenResponse requestSecurityTokenResponse)
			: base(serviceConfiguration, requestSecurityTokenResponse)
		{
		}

		public OrganizationServiceProxy(IServiceManagement<IOrganizationService> serviceManagement, RequestSecurityTokenResponse securityTokenResponse)
			: this(serviceManagement as IServiceConfiguration<IOrganizationService>, securityTokenResponse)
		{

		}

		protected override OrganizationServiceClient CreateService()
		{
			return new OrganizationServiceClient(ServiceBinding, ServiceAddress);
		}

		public override void ExecuteRequest(OrganizationRequest request)
		{
			using (OperationContextScope scope = new OperationContextScope(Service.InnerChannel))
			{
				// Add the authentication header with the token, and any other headers needed.
				SetToken();

				Service.ExecuteCompleted += ServiceClientExecuteCompleted;
				Service.ExecuteAsync(request, scope);
			}
		}

		public TimeSpan OperationTimeout
		{
			get { return Service.InnerChannel.OperationTimeout; }
			set { Service.InnerChannel.OperationTimeout = value; }
		}

		#region Create
		public void Create(Entity entity)
		{
			using (OperationContextScope scope = new OperationContextScope(Service.InnerChannel))
			{
				// Add the authentication header with the token, and any other headers needed.
				SetToken();

				Service.CreateCompleted += CreateCompletedHandler;
				Service.CreateAsync(entity, scope);
			}
		}

		private void CreateCompletedHandler(object sender, CreateCompletedEventArgs e)
		{
			OnCreateCompleted(e);
		}

		private void OnCreateCompleted(CreateCompletedEventArgs args)
		{
			if (CreateCompleted != null)
			{
				CreateCompleted(this, args);
			}
		}
		public event EventHandler<CreateCompletedEventArgs> CreateCompleted;
		#endregion

		#region Retrieve
		public void Retrieve(string entityName, Guid id, ColumnSet columnSet)
		{
			using (OperationContextScope scope = new OperationContextScope(Service.InnerChannel))
			{
				// Add the authentication header with the token, and any other headers needed.
				SetToken();

				Service.RetrieveCompleted += RetrieveCompletedHandler;
				Service.RetrieveAsync(entityName, id, columnSet, scope);
			}
		}

		private void RetrieveCompletedHandler(object sender, RetrieveCompletedEventArgs e)
		{
			OnRetrieveCompleted(e);
		}

		private void OnRetrieveCompleted(RetrieveCompletedEventArgs args)
		{
			if (RetrieveCompleted != null)
			{
				RetrieveCompleted(this, args);
			}
		}
		public event EventHandler<RetrieveCompletedEventArgs> RetrieveCompleted;
		#endregion

		#region Update
		public void Update(Entity entity)
		{
			using (OperationContextScope scope = new OperationContextScope(Service.InnerChannel))
			{
				// Add the authentication header with the token, and any other headers needed.
				SetToken();

				Service.UpdateCompleted += UpdateCompletedHandler;
				Service.UpdateAsync(entity);
			}
		}

		private void UpdateCompletedHandler(object sender, AsyncCompletedEventArgs e)
		{
			OnUpdateCompleted(e);
		}

		private void OnUpdateCompleted(AsyncCompletedEventArgs args)
		{
			if (UpdateCompleted != null)
			{
				UpdateCompleted(this, args);
			}
		}
		public event EventHandler<AsyncCompletedEventArgs> UpdateCompleted;
		#endregion

		#region Delete
		public void Delete(string entityName, Guid id)
		{
			using (OperationContextScope scope = new OperationContextScope(Service.InnerChannel))
			{
				// Add the authentication header with the token, and any other headers needed.
				SetToken();

				Service.DeleteCompleted += DeleteCompletedHandler;
				Service.DeleteAsync(entityName, id, scope);
			}
		}

		private void DeleteCompletedHandler(object sender, AsyncCompletedEventArgs e)
		{
			OnDeleteCompleted(e);
		}

		private void OnDeleteCompleted(AsyncCompletedEventArgs args)
		{
			if (DeleteCompleted != null)
			{
				DeleteCompleted(this, args);
			}
		}
		public event EventHandler<AsyncCompletedEventArgs> DeleteCompleted;
		#endregion

		#region RetrieveMultiple
		public void RetrieveMultiple(QueryBase query)
		{
			using (OperationContextScope scope = new OperationContextScope(Service.InnerChannel))
			{
				// Add the authentication header with the token, and any other headers needed.
				SetToken();

				Service.RetrieveMultipleCompleted += RetrieveMultipleCompletedHandler;
				Service.RetrieveMultipleAsync(query, scope);
			}
		}

		private void RetrieveMultipleCompletedHandler(object sender, RetrieveMultipleCompletedEventArgs e)
		{
			OnRetrieveMultipleCompleted(e);
		}

		private void OnRetrieveMultipleCompleted(RetrieveMultipleCompletedEventArgs args)
		{
			if (RetrieveMultipleCompleted != null)
			{
				RetrieveMultipleCompleted(this, args);
			}
		}
		public event EventHandler<RetrieveMultipleCompletedEventArgs> RetrieveMultipleCompleted;
		#endregion

		#region Associate
		public void Associate(string entityName, Guid entityId, Relationship relationship,
									   EntityReferenceCollection relatedEntities)
		{
			using (OperationContextScope scope = new OperationContextScope(Service.InnerChannel))
			{
				// Add the authentication header with the token, and any other headers needed.
				SetToken();

				Service.AssociateCompleted += AssociateCompleted;
				Service.AssociateAsync(entityName, entityId, relationship, relatedEntities);
			}
		}

		private void AssociateCompletedHandler(object sender, AsyncCompletedEventArgs e)
		{
			OnAssociateCompleted(e);
		}

		private void OnAssociateCompleted(AsyncCompletedEventArgs args)
		{
			if (AssociateCompleted != null)
			{
				AssociateCompleted(this, args);
			}
		}
		public event EventHandler<AsyncCompletedEventArgs> AssociateCompleted;
		#endregion

		#region Disassociate
		public void Disassociate(string entityName, Guid entityId, Relationship relationship,
									   EntityReferenceCollection relatedEntities)
		{
			using (OperationContextScope scope = new OperationContextScope(Service.InnerChannel))
			{
				// Add the authentication header with the token, and any other headers needed.
				SetToken();

				Service.DisassociateCompleted += DisassociateCompleted;
				Service.DisassociateAsync(entityName, entityId, relationship, relatedEntities);
			}
		}

		private void DisassociateCompletedHandler(object sender, AsyncCompletedEventArgs e)
		{
			OnDisassociateCompleted(e);
		}

		private void OnDisassociateCompleted(AsyncCompletedEventArgs args)
		{
			if (DisassociateCompleted != null)
			{
				DisassociateCompleted(this, args);
			}
		}
		public event EventHandler<AsyncCompletedEventArgs> DisassociateCompleted;
		#endregion
	}
}
